package com.deep.ware.service.impl;

import com.deep.common.model.constant.WareConstant;
import com.deep.ware.model.entity.PurchaseDetailEntity;
import com.deep.ware.model.vo.MergePurchaseVO;
import com.deep.ware.model.vo.PurchaseFinishVO;
import com.deep.ware.service.PurchaseDetailService;
import com.deep.ware.service.WareSkuService;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deep.common.utils.PageUtils;
import com.deep.common.utils.Query;

import com.deep.ware.dao.PurchaseDao;
import com.deep.ware.model.entity.PurchaseEntity;
import com.deep.ware.service.PurchaseService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;


@Service("purchaseService")
public class PurchaseServiceImpl extends ServiceImpl<PurchaseDao, PurchaseEntity> implements PurchaseService {

    @Autowired
    private PurchaseDetailService detailService;

    @Autowired
    private WareSkuService wareSkuService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryUnreceivedPurchase(@RequestParam Map<String, Object> params) {
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>()
                        .eq("status", WareConstant.PurchaseDetailStatusEnum.CREATED).or()
                        .eq("status", WareConstant.PurchaseDetailStatusEnum.ASSIGNED)
        );

        return new PageUtils(page);
    }

    /**
     * 修改、创建采购单
     *
     * @param mergeVO
     */
    @Transactional
    @Override
    public void mergePurchase(MergePurchaseVO mergeVO) {
        Assert.notNull(mergeVO, "mergePurchaseVO 不能为空!");

        Long purchaseId = mergeVO.getPurchaseId();
        // 如果采购id为null 说明没选采购单
        if (purchaseId == null) {
            // 新建采购单
            PurchaseEntity purchaseEntity = new PurchaseEntity();
            purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
            purchaseEntity.setCreateTime(new Date());
            purchaseEntity.setUpdateTime(new Date());
            this.save(purchaseEntity);
            purchaseId = purchaseEntity.getId();
        }

        // 采购实体id集合
        List<Long> items = mergeVO.getItems();

        PurchaseEntity purchaseEntity = new PurchaseEntity();
        // 修改兵过滤符合条件的采购实体状态
        List<PurchaseDetailEntity> detailEntities = detailService.getBaseMapper().selectBatchIds(items)
                .stream().filter(entity -> {
                    // 如果存在之前采购异常的项目 状态修改为 已分配
                    if (entity.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()) {
                        purchaseEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());
                        purchaseEntity.setId(entity.getPurchaseId());
                        this.updateById(purchaseEntity);
                    }
                    // 过滤所有大于 [已分配] 状态的采购单(即返回新建、已分配、采购失败的采购单)
                    return entity.getStatus() < WareConstant.PurchaseDetailStatusEnum.BUYING.getCode()
                            || entity.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode();
                }).collect(Collectors.toList());

        // 将符合条件采购实体id重新赋值给采购实体id集合
        items = detailEntities.stream().map(entity -> entity.getId()).collect(Collectors.toList());
        if (items.size() <= 0) {
            throw new IllegalArgumentException("合并采购单异常!");
        }
        // 设置仓库id
        purchaseEntity.setWareId(detailEntities.get(0).getWareId());
        Long finalPurchaseId = purchaseId;

        // 给采购单设置各种属性
        List<PurchaseDetailEntity> purchaseDetailEntities = items.stream().map(item -> {
            PurchaseDetailEntity entity = new PurchaseDetailEntity();
            entity.setId(item);
            entity.setPurchaseId(finalPurchaseId);
            entity.setStatus(WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());
            return entity;
        }).collect(Collectors.toList());

        // 更新采购单详情集合
        detailService.updateBatchById(purchaseDetailEntities);
        // 更新整单
        purchaseEntity.setId(purchaseId);
        // purchaseEntity.setUpdateTime(new Date());
        this.updateById(purchaseEntity);
    }

    @Override
    public void receivePurchase(List<Long> ids) {
        Assert.notNull(ids, "采购单id不能为空!");

        List<PurchaseEntity> purchaseEntities = ids.stream()
                .map(id -> this.getById(id))
                .filter(item -> {
                    // 1、只能领取采购单状态为新建或已分配状态
                    return item.getStatus() == WareConstant.PurchaseStatusEnum.CREATED.getCode()
                            || item.getStatus() == WareConstant.PurchaseStatusEnum.ASSIGNED.getCode();
                }).map(item -> {
                    // 2、改变采购单的状态
                    item.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode());
                    return item;
                }).collect(Collectors.toList());
        this.updateBatchById(purchaseEntities);

        // 3、改变采购项的状态
        purchaseEntities.forEach(item -> {
            List<PurchaseDetailEntity> entities = detailService.getBaseMapper()
                    .selectList(new QueryWrapper<PurchaseDetailEntity>().eq("purchase_id", item.getId()));

            // 收集所有需要更新的采购单id
            List<PurchaseDetailEntity> detailEntities = entities.stream().map(entity -> {
                entity.setStatus(WareConstant.PurchaseDetailStatusEnum.BUYING.getCode());
                return entity;
            }).collect(Collectors.toList());

            // 批量更新订单项
            detailService.updateBatchById(detailEntities);
        });

    }

    @Transactional
    @Override
    public void finishPurchase(PurchaseFinishVO finishVO) {
        Assert.notNull(finishVO, "finishVO 不能为空!");
        // 1、改变采购项的状态
        AtomicReference<Boolean> flag = new AtomicReference<>(true);
        // 保存采购成功的集合
        ArrayList<PurchaseDetailEntity> finishPurchase = new ArrayList<>();

        // 采购总价
        BigDecimal totalPrice = new BigDecimal(0);

        finishVO.getItems().forEach(item -> {
            PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
            // 采购失败
            if (item.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()) {
                flag.set(false);
                detailEntity.setStatus(item.getStatus());
            } else {
                // 2、采购成功的进行入库
                detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.FINISH.getCode());
                // 获取采购项的详细信息
                PurchaseDetailEntity entity = detailService.getById(item.getItemId());
                // 新增库存，并返回商品价格
                BigDecimal price = wareSkuService.addStock(entity.getSkuId(), entity.getWareId(), entity.getSkuNum());

                if (price.compareTo(BigDecimal.valueOf(0)) > 0) {
                    totalPrice.add(BigDecimal.valueOf(entity.getSkuNum()).multiply(price));
                }
                detailEntity.setSkuPrice(price);
            }
            // 设置采购成功的id
            detailEntity.setId(item.getItemId());
            // 将采购成功的添加到集合
            finishPurchase.add(detailEntity);
        });
        // 更新从采购项状态
        detailService.updateBatchById(finishPurchase);

        // 对采购单的状态进行更新
        // 1、改变采购单状态(未更新)
        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(finishVO.getId());
        purchaseEntity.setAmount(totalPrice);
        purchaseEntity.setStatus(flag.get() ? WareConstant.PurchaseStatusEnum.FINISH.getCode()
                : WareConstant.PurchaseStatusEnum.HASERROR.getCode());

        this.updateById(purchaseEntity);
    }
}